﻿using System;
using System.Data;
using System.Configuration;
using System.Text;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections;
using System.Collections.Generic;

using SSN.Objects;
using SSN.WebFramework.Controls;
using SSN.WebFramework.Logging;
using System.Reflection;

namespace SSN.WebFramework
{
    public abstract class GenPage : Page
    {
        /// <summary>
        /// Gets or sets the control that has default focus on page load.
        /// </summary>
        public Control ControlWithFocus { get; set; }

        private SecurityManager _SecurityManager;
        /// <summary>
        /// Returns the current SecurityManager.
        /// </summary>
        public SecurityManager SecurityManager
        {
            get
            {
                if (_SecurityManager == null)
                {
                    _SecurityManager = new SecurityManager(Session);
                }

                return _SecurityManager;
            }
        }

        private ParameterManager _ParameterManager = null;
        /// <summary>
        /// Returns the current ParameterManager.
        /// </summary>
        public ParameterManager ParameterManager
        {
            get
            {
                if (_ParameterManager == null)
                    _ParameterManager = new ParameterManager(SecurityManager, Server, Request.QueryString);
                return _ParameterManager;
            }
        }

        public void Page_Load(object o, EventArgs e)
        {
            try
            {
                InitPage();
            }
            catch (Exception ex)
            {
                ReportError(ex);
            }
        }

        /// <summary>
        /// Handled by the page's normal life cycle.
        /// </summary>
        /// <param name="o"></param>
        /// <param name="e"></param>
        protected override void OnPreInit(EventArgs e)
        {
            if (!CheckSecurity())
            {
                Response.Redirect(ErrorManager.NotAuthorizedPage);
            }
            
            MaintainScrollPositionOnPostBack = false;
            ClientIDMode = System.Web.UI.ClientIDMode.Static;

            if (!Page.IsPostBack)
            {
                LogView();
            }

            base.OnPreInit(e);
        }

        /// <summary>
        /// Must be implemented by every page.
        /// </summary>
        /// <returns></returns>
        public abstract void InitPage();

        /// <summary>
        /// Logs the view.
        /// </summary>
        private void LogView()
        {
            LogEntry toLog = new LogEntry();
            toLog.RawURL = Request.RawUrl;
            toLog.PageURL = Request.FilePath;
            toLog.BrowserCode = Request.UserAgent;
            toLog.OSCode = Request.Browser.Platform;

            toLog.Parameters = new System.Collections.Specialized.NameValueCollection();

            foreach (string s in ParameterManager.Keys)
            {
                toLog.Parameters.Add(s, ParameterManager[s]);
            }

            toLog.Server = Environment.MachineName;
            toLog.UserID = SecurityManager.IsLoggedIn ? SecurityManager.UserID : "Not Authenticated";
            toLog.UserIP = Request.UserHostAddress;

            LoggingManager.AddEntry(toLog);
        }

        /// <summary>
        /// Returns turn for GenPages, for AuthPages, override.
        /// </summary>
        /// <returns>Whether the user has access to the page.</returns>
        public virtual bool CheckSecurity() { return true; }

        /// <summary>
        /// Indicates whether the page should be tracked. Override for individual pages to turn tracking off.
        /// </summary>
        public virtual bool TrackPage { get { return true; } }

        /// <summary>
        /// Logs the current url so if the session logs out, the user can be redirected to the intended page.
        /// </summary>
        protected string LoggedUrl
        {
            get { return Session["log_url"].ToString(); }
            set { Session["log_url"] = value; }
        }

        /// <summary>
        /// Returns whether the current user is an administrator of the site.
        /// </summary>
        public bool IsAdmin
        {
            get
            {
                return SecurityManager.SecurityContext.IsInRole(WebSettings.AdministrationRole);
            }
        }

        /// <summary>
        /// Binds the object to the page. Any control with that implements IBindable will have Bind called on it, passing the object.
        /// </summary>
        /// <param name="obj"></param>
	   public void BindObjectToControls(object obj) {
		   if(!Page.IsPostBack) {
			   foreach(IBindable bindC in BindableControls(this)) {
				   if(bindC.BindProperty == null)
					   bindC.BindProperty = ((Control)bindC).ID;
				   bindC.BindFromObject(obj);
			   }
		   }
	   }

	   /// <summary>
	   /// Binds the values in the page controls to the object. Any control with that implements IBindable will have Bind called on it, passing the object.
	   /// </summary>
	   /// <param name="obj"></param>
	   public void BindControlsToObject(object obj) {
		   foreach(IBindable bindC in BindableControls(this)) {
			   if(bindC.BindProperty == null)
				   bindC.BindProperty = ((Control)bindC).ID;
			   bindC.BindToObject(obj);
		   }
	   }

	   /// <summary>
	   /// Retrieves all the controls that implement IBindable.
	   /// </summary>
	   /// <param name="control"></param>
	   /// <returns></returns>
	   private IEnumerable<IBindable> BindableControls(Control control) {
		   List<IBindable> controls = new List<IBindable>();
		   foreach(Control c in control.Controls) {
			   controls.AddRange(BindableControls(c)); //Depth-first so child controls get bound before parents
			   if(c is IBindable) {
				   controls.Add((IBindable)c);
			   }
		   }
		   return controls;
	   }


        /// TODO: Code to parse out the error and email it.
        
        public void ReportError(Exception e)
        {
            ReportError(e.Message);
        }

        public void ReportError(string s)
        {
            Response.Redirect(ConfigManager.GetConfigSetting("errorpage", "/first.aspx"));
        }

        public void NotAuthorized()
        {
            Response.Redirect(ConfigManager.GetConfigSetting("notauthpage", "/first.aspx"));
        }
    }
}
